package com.involveinnovation.chatserver.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.involveinnovation.chatserver.controller.Model.ChatRoom;
import com.involveinnovation.chatserver.controller.Model.Message;
import com.involveinnovation.chatserver.controller.Model.Message2;
import com.involveinnovation.chatserver.controller.Model.UserList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 15128
 */
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {

    static Log log = LogFactory.get(WebSocketServer.class);

    /** 静态变量标记当前连接数 */
    private static int onlineCount = 0;

    private static int roomCount = 0;

    /**concurrent包的线程安全set, 用来存放每个客户端对应的MyWebSocket对象, 其实就是客户端的线程集合 */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    private static Vector<ChatRoom> chatrooms = new Vector<ChatRoom>();

    /** 与某个客户端的连接会话，需要通过它给客户端发送数据*/
    private Session session;

    /** userId */
    private String userId = "系统";

    /**
     * 连接成功建立
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId){

        this.session = session;
        this.userId = userId;
        log.info(userId);
        /** 如果已经建立过连接，则移除该连接，并重新放入 */
        if(webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
        } else {
            webSocketMap.put(userId, this);
            addOnlineCount();
        }
        log.info("用户连接:" + userId + ", 当前在线人数为: " + getOnlineCount());

        try {
            sendMessage("连接成功");
            String message = getOnlineUser();
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常！！！！！！！");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
//        if(webSocketMap.containsKey(userId)) {
//            webSocketMap.remove(userId);
//            subOnlineCount();
//        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws SQLException {
        log.info("用户消息：" + userId + ",报文:" + message);

        // System.out.println("message:" + message);
        // 可以群发消息
        // 消息保存到redis数据库
        if(StringUtils.isNotBlank(message)) {
            try {
                // 解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
                // System.out.println(jsonObject.getString("fromUserId"));
                // 追加发送人（防止串改）
                jsonObject.put("fromUserId", this.userId);
                if(Objects.equals(jsonObject.getString("type"), "登录")){
                    Message2 msg = new Message2();
                    msg.setFromUserId(this.userId);
                    msg.setType("登录");
                    String message2 = getOnlineUser();
                    msg.setContentText(JSON.parseObject(message2).getString("userList"));
                    sendInfoByUser(msg);
                }
                else if(Objects.equals(jsonObject.getString("type"), "登出")){
                    Message2 msg = new Message2();
                    if(webSocketMap.containsKey(this.userId)) {
                        webSocketMap.remove(this.userId);
                        subOnlineCount();
                    }
                    exitAllRoom(this.userId);
                    msg.setFromUserId(this.userId);
                    msg.setType("登出");
                    String message2 = getOnlineUser();
                    msg.setContentText(JSON.parseObject(message2).getString("userList"));
                    sendInfoByUser(msg);
                }
                else if(Objects.equals(jsonObject.getString("type"), "创建房间")){
                    if (roomExisted(jsonObject.getInteger("roomNum"))) {
                        Message2 message2 = new Message2();
                        message2.setContentText("房间已创建");
                        message2.setType("房间创建失败");
                        message2.setToUserId(userId);
                        webSocketMap.get(userId).sendMessage(message2.toString());
                        log.info("房间已创建");
                    } else {
                        ChatRoom chatRoom = new ChatRoom();
                        chatRoom.setRoomNum(jsonObject.getInteger("roomNum"));
                        chatRoom.setOnlineCount(1);
                        ArrayList<String> list = new ArrayList<String>();
                        list.add(userId);
                        chatRoom.setList(list);
                        chatrooms.add(chatRoom);
                        chatRoom.setType("房间创建成功");
                        log.info("房间创建完毕");
                        WebSocketServer.addOnlineRoom();
//                        Message2 message2 = new Message2();
//                        message2.setContentText("房间"+jsonObject.getInteger("roomNum")+"创建完毕");
//                        message2.setType("房间创建成功");
//                        message2.setToUserId(userId);

                        webSocketMap.get(userId).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));
                        // webSocketMap.get(userId).sendMessage(message2.toString());
                    }
                }
                else if(Objects.equals(jsonObject.getString("type"), "加入房间")){
                    if (roomExisted(jsonObject.getInteger("roomNum"))) {
                        ChatRoom chatRoom = addToRoom(jsonObject.getInteger("roomNum"), userId);
                        if ( chatRoom == null ) {
                            log.info("房间已满");
                            Message2 message2 = new Message2();
                            message2.setContentText("房间"+jsonObject.getInteger("roomNum")+"已满");
                            message2.setType("房间已满");
                            message2.setToUserId(userId);
                            webSocketMap.get(userId).sendMessage(message2.toString());
                        }
                        else{
                            chatRoom.setType("加入房间成功");
                            System.out.println(JSON.toJSONString(JSON.toJSON(chatRoom)));
                            // this.session.getBasicRemote().sendObject(JSON.toJSON(chatRoom));
                            webSocketMap.get(userId).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));

                            // 向房间其他人打招呼
                            ArrayList list = chatRoom.getList();
                            for(int i=0;i< list.size(); i++){
                                if(!list.get(i).equals(userId)){
                                    chatRoom.setType("房间人员变动");
                                    webSocketMap.get(list.get(i)).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));
                                }
                            }
                        }
                    } else {
                        log.info("房间不存在");
                        Message2 message2 = new Message2();
                        message2.setContentText("房间"+jsonObject.getInteger("roomNum")+"不存在");
                        message2.setType("房间不存在");
                        message2.setToUserId(userId);
                        webSocketMap.get(userId).sendMessage(message2.toString());
                    }
                }
                else if(Objects.equals(jsonObject.getString("type"), "退出房间")){
                    exitRoom(jsonObject.getInteger("roomNum"), userId);
                    Message2 msg = new Message2();
                    msg.setType("退出房间");
                    msg.setRoomNum(jsonObject.getString("roomNum"));
                    sendInfoByUser(msg);

                }
                else if(Objects.equals(jsonObject.getString("type"), "房间聊天")){
                    for(int i=0;i<roomCount;i++){
                        ChatRoom chatRoom = chatrooms.get(i);
                        if(chatRoom.getRoomNum() == jsonObject.getInteger("roomNum")) {
                            chatRoom.setType("房间聊天");
                            Message2 msg = new Message2();
                            msg.setContentText(jsonObject.getString("contentText"));
                            msg.setFromUserId(this.userId);
                            msg.setType("房间聊天");
                            msg.setRoomNum(jsonObject.getString("roomNum"));
                            chatRoom.getMessages().add(msg);

                            webSocketMap.get(userId).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));

                            // 向房间其他人转发
                            ArrayList list = chatRoom.getList();
                            for(int j=0;j< list.size(); j++){
                                if(!list.get(j).equals(userId)){
                                    chatRoom.setType("房间聊天");
                                    webSocketMap.get(list.get(j)).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));
                                }
                            }
                        }
                    }
                }
                else if(Objects.equals(jsonObject.getString("type"), "群发")){
                    Message2 msg = new Message2();
                    msg.setContentText(jsonObject.getString("contentText"));
                    msg.setFromUserId(jsonObject.getString("fromUserId"));
                    msg.setType("群发");
                    sendInfoByUser(msg);
                }
                else { // 私聊
                    String toUserId = jsonObject.getString("toUserId");
                    // 传送给对应用户的websocket
                    if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
                        webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
                    } else {
                        log.error("请求的userId:" + toUserId + "不在该服务器上");
                        // 存储到Mysql或Redis（后续再说）
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Error
     */
    @OnError
    public void onError(@PathParam("userId") String userId,
                        Throwable throwable,
                        Session session) {
        log.info("[WebSocketServer] Connection Exception : userId = "+ userId + " , throwable = " + throwable.getMessage());
    }


    /**
     * 实现服务器推送消息
     * @param message 推送的消息
     * @return
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 系统发送自定义消息
     * @return
     */
    public static void sendInfoBySystem(Message2 message) throws IOException {
        String userId = "";
        // log.info("发送消息到:" + userId + ",报文:" + message.getContentText());
        try {
            for(Map.Entry<String, WebSocketServer> entry: webSocketMap.entrySet()) {
                userId = entry.getKey();
                if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
                    webSocketMap.get(userId).sendMessage(message.toString());
                } else {
                    log.error("用户" + userId + "不在线");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用户发送全体消息
     * @return
     */
    public static void sendInfoByUser(Message2 message) throws IOException {
        String userId = "";
        try {
            for(Map.Entry<String, WebSocketServer> entry: webSocketMap.entrySet()) {
                userId = entry.getKey();
                message.setToUserId(userId);
                if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
                    webSocketMap.get(userId).sendMessage(message.toString());
                } else {
                    log.error("用户" + userId + "不在线");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static synchronized String getOnlineUser() {
        ArrayList list = new ArrayList();
        for(Map.Entry<String, WebSocketServer> entry: webSocketMap.entrySet()) {
            list.add(entry.getKey());
        }

        UserList userList = new UserList();
        userList.setUserList(list);
        return userList.toString();
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
    public static synchronized void addOnlineRoom() {
        WebSocketServer.roomCount++;
    }
    public static synchronized void subOnlineRoom() {
        WebSocketServer.roomCount--;
    }

    public static boolean roomExisted(int num) {
        for(int i = 0; i < roomCount; i++) {
            if(chatrooms.get(i).getRoomNum() == num) {
                return true;
            }
        }
        return false;
    }

    public static ChatRoom addToRoom(int roomNum, String userId) {
        for(int i = 0; i < roomCount; i++) {
            ChatRoom chatRoom = chatrooms.get(i);
            if(chatRoom.getRoomNum() == roomNum) {
                if (chatRoom.getOnlineCount() >= chatRoom.getLimit()) {
                    return null;
                }
                ArrayList list = chatRoom.getList();
                for(int j = 0; j<list.size(); j++){
                    if(list.get(j).equals(userId)) {
                        return null;
                    }
                }
                list.add(userId);
                chatRoom.setList(list);
                chatRoom.setOnlineCount(chatRoom.getOnlineCount()+1);
                return chatRoom;
            }
        }
        return null;
    }

    public static void exitRoom(int roomNum, String userId) throws IOException {
        for(int i = 0; i < roomCount; i++) {
            ChatRoom chatRoom = chatrooms.get(i);
            if(chatRoom.getRoomNum() == roomNum) {
                ArrayList list = chatRoom.getList();
                list.remove(userId);
                chatRoom.setList(list);
                chatRoom.setOnlineCount(chatRoom.getOnlineCount()-1);

                // 向房间其他人打招呼
                list = chatRoom.getList();
                for(int j=0;j< list.size(); j++){
                    if(!list.get(j).equals(userId)){
                        chatRoom.setType("房间人员变动");
                        webSocketMap.get(list.get(j)).sendMessage(JSON.toJSONString(JSON.toJSON(chatRoom)));
                    }
                }

                if(chatRoom.getOnlineCount() == 0) {
                    chatrooms.remove(i);
                    roomCount--;
                }

                return ;
            }
        }
        return ;
    }

    public static void exitAllRoom(String userId) {
        for(int i = 0; i < roomCount; i++) {
            ChatRoom chatRoom = chatrooms.get(i);
            ArrayList list = chatRoom.getList();
            try{
                list.remove(userId);
                chatRoom.setList(list);
                chatRoom.setOnlineCount(chatRoom.getOnlineCount()-1);
                if(chatRoom.getOnlineCount() == 0) {
                    chatrooms.remove(i);
                    roomCount--;
                }
            } catch (Error e) {
                e.printStackTrace();
            }
            return ;
        }
        return ;
    }

}
